#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <queue>
#include <stack>
#include <vector>
#include <iostream>
using namespace std;

#define MAX_SIZE 500
#define INF 10000
typedef struct Vnode *PtrToVNode;
struct Vnode
{
    int id;
    int length;
    int cost;
    PtrToVNode Near;
};

//重载运算符 以适用priority_queue的greater按length来排
bool operator<(Vnode a,Vnode b)
{
    if(a.length == b.length)
        return a.cost < b.cost;
    return a.length < b.length;
}
bool operator>(Vnode a,Vnode b)
{
    if(a.length == b.length)
        return a.cost > b.cost;
    return a.length > b.length;
}
typedef struct LGraph
{
    PtrToVNode Near;
}AdjList[MAX_SIZE];

int main()
{
    int N, M, S, D, v1, v2, l, c;
    scanf("%d %d %d %d", &N, &M, &S, &D);
    int cost[MAX_SIZE][MAX_SIZE],dis[MAX_SIZE][MAX_SIZE];

    PtrToVNode temp,temp_near;
    AdjList LGraph;
    priority_queue<Vnode, vector<Vnode>, greater<Vnode>> minheap;

    for (int i = 0; i < N;i++)
    {
        LGraph[i].Near = NULL;
    }

    for (int i = 0; i < N;i++)
        for (int j = 0; j < N;j++)
        {
            cost[i][j] = INF;
            dis[i][j] = INF;
        }

    for (int i = 0; i < M; i++)
    {
        scanf("%d %d %d %d", &v1, &v2, &l, &c);
        cost[v1][v2] = c;
        cost[v2][v1] = c;
        dis[v1][v2] = l;
        dis[v2][v1] = l;
        temp = (PtrToVNode)malloc(sizeof(struct Vnode));
        temp->id = v2;
        temp->length = INF;
        temp->cost = INF;
        temp->Near = LGraph[v1].Near;
        LGraph[v1].Near = temp;

        //无向图 双边连接
        temp = (PtrToVNode)malloc(sizeof(struct Vnode));
        temp->id = v1;
        temp->length = INF;
        temp->cost = INF;
        temp->Near = LGraph[v2].Near;
        LGraph[v2].Near = temp;
    }

    //dijkstra -> but with min heap modify no visit
    //start node insert heap
    temp = (PtrToVNode)malloc(sizeof(struct Vnode));
    temp->id = S;
    temp->length = 0;
    temp->cost = 0;
    temp->Near = LGraph[S].Near;
    minheap.push(*temp);

    // init some temp variables
    int V, W;

    //from start node
    while(minheap.top().id != D)
    {
        temp = (PtrToVNode)malloc(sizeof(struct Vnode));
        temp_near = (PtrToVNode)malloc(sizeof(struct Vnode));
        *temp = minheap.top();
        minheap.pop();
        temp_near = temp;
        temp = LGraph[temp->id].Near;
        V = temp_near->id;
        //insert all around nodes
        while(temp!=NULL)
        {
            W = temp->id;
            if (temp_near->length + dis[V][W] < temp->length || (temp_near->length + dis[V][W] == temp->length&&temp_near->cost + cost[V][W] < temp->cost))
            {
                temp->length = temp_near->length + dis[V][W];
                temp->cost = temp_near->cost + cost[V][W];
                minheap.push(*temp);
            }
            temp = temp->Near;
        }
    }
    printf("%d %d", minheap.top().length, minheap.top().cost);
    return 0;
}